home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
et
/
et3_0-a1.lha
/
et3
/
src
/
GapText.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-08-26
|
9KB
|
407 lines
#ifdef __GNUG__
#pragma implementation
#endif
#include "GapText.h"
#include "Class.h"
#include "RegularExp.h"
#include "Error.h"
#include "Math.h"
const int cShrinkFactor = 2,
cMaxOutput = 500,
cInitialSize = 16;
//---- GapText -----------------------------------------------------------------
NewMetaImpl(GapText,Text, (T(size), T(length), T(part1len), T(gaplen),
TV(body, part1len), TV(body2, part2len)));
//---- private -----------------------------------------------------------------
void GapText::Update(int l)
{
part1len= l;
gaplen= size - length;
part2body= body + gaplen;
part2len= length - part1len;
body2= part2body + part1len;
}
void GapText::MoveGap(int to)
{
if (to == part1len)
return;
if (part1len > to)
MemCpy(body+to+gaplen, body+to, part1len-to);
else
MemCpy(body+part1len, body+part1len+gaplen, to-part1len);
part1len= to;
}
void GapText::CopyTo(byte *dst, int from, int to)
{
// Copy Text between 'from' and 'to' to 'dst'
int beforegap= Math::Max(0, part1len-from) - Math::Max(0, part1len-to);
int aftergap= Math::Max(0, to - part1len) - Math::Max(0, from-part1len);
if (beforegap)
MemCpy(dst, body+from, beforegap);
if (aftergap)
MemCpy(dst+beforegap, part2body+Math::Max(part1len, from), aftergap);
}
void GapText::Expand(int to, int moveto)
{
// Expand size of Text to 'to'
byte *pos, *part2;
if (to < size)
return;
if (moveto > length)
moveto= length;
size= to;
pos= new byte[size];
part2= pos+size-length;
if (moveto < part1len) {
MemCpy(pos, body, moveto);
MemCpy(part2+moveto, body+moveto, part1len-moveto);
MemCpy(part2+part1len, body2, length-part1len);
} else {
MemCpy(pos, body, part1len);
MemCpy(pos+part1len, body2, moveto-part1len);
MemCpy(part2+moveto, part2body+moveto, length-moveto);
}
delete body;
body= pos;
Update(moveto);
}
void GapText::Shrink(int to)
{
byte *pos;
if ((to == 0) || (to < length))
to= size/cShrinkFactor + 1;
if ( (to > size) || (to < length) )
return;
size= to;
pos= new byte[size];
MemCpy(pos, body, part1len);
MemCpy(pos+part1len, body+part1len+gaplen, part2len);
delete body;
body= pos;
Update(length);
}
GapText::GapText(int s, Font *fd)
{
size= Math::Max(cInitialSize, s);
body= new byte[size];
Init(0, fd);
}
GapText::GapText(byte *buf, int len, Font *fd)
{
if (len < 0)
len= strlen((char*)buf);
size= Math::Max(cInitialSize, len);
body= new byte[size];
MemCpy(body, buf, len);
Init(len, fd);
}
void GapText::InitNew()
{
Text::InitNew();
Init(0, gSysFont);
}
void GapText::Init(int l, Font *fd)
{
length= l;
Update(l);
charStyle= new_CharStyle(fd);
SetDefTab(fd->Width(' ')*8);
if (!IsTerminated())
Terminate();
}
GapText::~GapText()
{
SafeDelete(body);
part2body= 0;
}
void GapText::Terminate()
{
if (IsTerminated())
return;
AddChar(Size(), '\0');
}
void GapText::AddChar(int at, byte b)
{
if (HighWaterMark(1))
Expand(GrowSize(size+1), Size());
else
MoveGap(at);
body[at]= b;
length+= 1;
Update(part1len+1);
}
void GapText::ReplaceRange(int from, int to, Text *tsrc, int sfrom, int sto)
{
GapText *src;
byte *buf= 0;
if (!CheckRange(End(), from, to))
Error("ReplaceRange", "out of range");
if (!tsrc->IsKindOf(GapText)) { // convert the text into a GapText
int s= sto-sfrom;
buf= new byte[s+1];
tsrc->CopyInStr(buf, s+1, sfrom, sto);
src= new GapText(buf, s);
sto= sto-sfrom;
sfrom= 0;
} else
src= (GapText *)tsrc;
int shift= (sto - sfrom) - (to - from);
if (HighWaterMark(shift))
Expand(GrowSize(size+shift), from);
else
MoveGap(from);
src->CopyTo(body+from, sfrom, sto);
length+= shift;
Update(part1len + (sto-sfrom));
if (LowWaterMark())
Shrink();
if (buf) {
delete src;
delete buf;
}
}
void GapText::CopyInStr(byte *str, int strsize, int from, int to)
{
if (!CheckRange(length, from, to))
Error("CopyInStr", "out of range");
to= Math::Min(to, from + strsize-1);
CopyTo(str, from, to);
str[to-from]= '\0';
}
Text *GapText::MakeScratchText(byte *buf, int len)
{
if (buf)
return new GapText(buf, len);
return new GapText(len);
}
int GapText::Search(RegularExp *rex, int *nMatched, int start, int range,
bool dir)
{
int pos;
if (dir == cSearchForward)
pos= rex->SearchForward2((char*)body, part1len,
(char*)(body+part1len+gaplen),
length-part1len, start, range, 0, nMatched);
else {
// BUG in RegularExp::SearchBackward2 ??
MoveGap(length);
pos= rex->SearchBackward((char*)body, nMatched, start, length, range, 0);
}
return pos;
}
byte *GapText::GetLineAccess(byte **buf, int from, int to)
{
if (!CheckRange(length, from, to))
return 0;
if ((part1len < to) && (part1len >= from)) {
// Gap is in between
*buf= (byte*) Realloc(*buf, to-from + 20);
for (int i= from; i < to; i++)
(*buf)[i-from]= CharAt(i);
return *buf;
}
if (part1len < from)
return &part2body[from];
return &body[from];
}
byte& GapText::operator[](int i)
{
//----> should notify about possible changes but how??
i= Math::Min(i, length-1);
if (i < part1len)
return body[i];
return part2body[i];
}
int GapText::Size()
{
return length;
}
TextIter *GapText::MakeIterator(int from, int to)
{
return new GapTextIter(this, from, to);
}
OStream& GapText::PrintOn(OStream& s)
{
Text::PrintOn(s);
MoveGap(length);
return s.PrintString(body, Size());
}
IStream& GapText::ReadFrom(IStream& s)
{
Text::ReadFrom(s);
SafeDelete(body);
s.ReadString(&body, &length);
size= length;
Update(length);
return s;
}
OStream& GapText::PrintOnAsPureText(OStream& s)
{
s.write(body, part1len);
s.write(body2, End() - part1len);
return s;
}
IStream& GapText::ReadFromAsPureText(IStream &s, long sizeHint)
{
char ch;
if (sizeHint > 0 && ((int)(sizeHint - size)) > 0)
Expand((int)sizeHint + 50);
if (body == 0)
body= new byte[size= 1024];
length= 0;
while (s.get(ch)) {
if (length >= size){
part2body= body ;
body= new byte[size= (size+1)*2];
MemCpy(body, part2body, length);
delete part2body;
}
body[length++]= ch;
}
Update(length);
Terminate();
if (!s.eof())
Error("ReadFromAsPureText", "missing EOF");
return s;
}
//---- GapTextIter -------------------------------------------------------------
GapTextIter::GapTextIter(Text *s, int from, int to) : TextIter(s, from, to)
{
if (!s->IsKindOf(GapText))
Error("GapTextIter::Error", "GapText expected (%s received)", s->ClassName());
st= (GapText*)s;
escape= st->GetMarkChar();
nextFontChange= st->GetNextFontChange(ce, sp);
if (sp == 0)
Error("GapTextIter::GapTextIter", "style is nil");
}
void GapTextIter::Reset(Text *s, int from, int to)
{
if (!s->IsKindOf(GapText))
Error("GapTextIter::Reset", "GapTextIter expected (%s received)",
s->ClassName());
st= (GapText*)s;
TextIter::Reset(s, from, to);
nextFontChange= st->GetNextFontChange(ce, sp);
escape= st->GetMarkChar();
if (sp == 0)
Error("GapTextIter::Reset", "style is nil");
}
int GapTextIter::GraphicSize(int at, LineDesc *l)
{
VisualMark *vmp= st->GetVisualMarkAt(at);
if (l)
l->Max(vmp->Base(), vmp->GetExtent().y);
return vmp->GetExtent().x;
}
int GapTextIter::operator()(int *w, LineDesc *ld)
{
unget= ce;
if (ce == upto )
return cEOT;
TestFontChange(sp);
int ch= CharAt(ce);
if (TestVisualMark(ce, ch)) {
if (w)
*w= GraphicSize(ce, ld);
}
else {
if (w)
*w= sp->GetFont()->Width(ch);
if (ld)
ld->FromFont(sp->GetFont());
}
ce++;
return ch;
}
int GapTextIter::Token(int *w, LineDesc *ld)
{
unget= ce;
*w= 0;
TestFontChange(sp);
if (ld)
ld->FromFont(sp->GetFont());
if (ce >= upto)
return cEOT;
register int ch= CharAt(ce);
if (TestVisualMark(ce ,ch)) {
*w= GraphicSize(ce, ld);
ce++;
return ch;
}
if (Iswordwrap(ch)) {
*w= sp->GetFont()->Width(ch);
ce++;
return ch;
}
while (ce < upto && !Iswordwrap(CharAt(ce)) && !TestVisualMark(ce, CharAt(ce))) {
if (TestFontChange(sp) && ld)
ld->Max(sp->GetFont());
ch= CharAt(ce++);
*w+= sp->GetFont()->Width(ch);
}
return ch;
}